#include "transContentPortRegist.hpp"

/////////////////////////////////////////////////////////////////
/// deal the stack response regsit message
///		get registed result, resigst port and other information from the packet
///
/// parameters:
///		buffer: the response buffer
///		index: the response buffer index in memory pool
///
/// return:
///		RESPONSE_RESULT_DELETE_RECORD: despose the regist instance, and free the relative port record
///		RESPONSE_RESULT_CHANGE_STATE: change the regits instance relative state to registed
///		RESPONSE_RESULT_NOACTION: no action
///////////////////////////////////////////////////////////////////
int TransContentPortRegist::response(char* buffer, int index){
	int mainCode, subCode;
	pthread_t pid;
	mRegistResult = transContentRegistProtocol::getPacketResult(buffer, DUMP_PROTOCOL_PACKET_IN);
	mainCode = transContentRegistProtocol::getPacketMainMessageCode(buffer, DUMP_PROTOCOL_PACKET_IN);
	subCode = transContentRegistProtocol::getPacketSubMessage(buffer, DUMP_PROTOCOL_PACKET_IN);
	mRegistedPort = transContentRegistProtocol::getPacketResultPort(buffer, DUMP_PROTOCOL_PACKET_IN);
	if((mRegistingType == REGIST_PORT_TYPE_APPLY && registCallback != NULL) || (mRegistingType == REGIST_PORT_TYPE_GET && gpcb != NULL)){
		//use sync method
		pthread_create(&pid, NULL, callbackRoute, this);
		pthread_detach(pid);
	}
	else{
		pthread_mutex_lock(&mutex_regist);
		pthread_cond_signal(&goOnCond);
		pthread_mutex_unlock(&mutex_regist);
	}
	sleep(1);
	/// result == 1 means regist sucessfully
	/// regsit finished
	if(mRegistResult != 1){
		TransContentMemory::getInstance()->releaseBuffer(index);
		canBeRemoved = 1;
		return RESPONSE_RESULT_DELETE_RECORD;
	}
	canBeRemoved = 0;
	return RESPONSE_RESULT_CHANGE_STATE;
}

void* TransContentPortRegist::callbackRoute(void* p){
	((TransContentPortRegist*)(p))->registFinished();
	return NULL;
}

void TransContentPortRegist::registFinished(){
	if(mRegistingType == REGIST_PORT_TYPE_APPLY && registCallback != NULL){
		registCallback(mRegistedPort);
		return;
	}
	gpcb(mRegistedPort);
	return;
}

/////////////////////////////////////////////////////////////////////
/// construct regist packet and send to stack
///		call regist protocol methods to make a regist packet and send to stack, get a port, check a port, or regist a port call this method
///
/// return:
///		E_TRANC_TIMEOUT: wait timeout
///		E_TRANC_NONBLOCK: call sync mthod, so will not block the caller
///		port: the regsit result port
///////////////////////////////////////////////////////////////////////
int TransContentPortRegist::regist(){
	/// construct packet
	char* buffer;
	int recordIndex=0;
	int length = 0;
	timespec ts = TransContentAssis::TimeTp2Ts(mTimeout);
	const char* localFifoName = TransContentSetting::getLocalFifoName();
	recordIndex = TransContentMemory::getInstance()->getBuffer(&buffer);
	if(E_TRANC_BUFFER_FULL == recordIndex){
		log_error("get space for regist failed, no buffer avaliable");
		return recordIndex;
	}

	transContentRegistProtocol::setPacketMainMessageCode(buffer, message_type_inner_regist_request);
	transContentRegistProtocol::setPacketSubMessage(buffer, mRegistingType);
	transContentRegistProtocol::setPacketTargetPort(buffer, mRegistingPort);
	transContentRegistProtocol::setPacketExistPort(buffer, mAlreadyPort);
	if(mAlreadyPort == -1){
		length = strlen(localFifoName);
		transContentRegistProtocol::setPacketPathLen(buffer, length);
		transContentRegistProtocol::setPacketPathValue(buffer, localFifoName, length);
	}
	length += 19;
	transContentRegistProtocol::setPacketLength(buffer, length);

	/// send to stack
	if(TransContentDispatcher::getInstance()->sendDataRegistToStack(buffer, length) != E_TRANC_SUCESS){
		log_error("send regist data to stack error!!");
		TransContentMemory::getInstance()->releaseBuffer(recordIndex);
		return E_TRANC_SystemError;
	}
	TransContentMemory::getInstance()->releaseBuffer(recordIndex);
	
	if((mRegistingType == REGIST_PORT_TYPE_APPLY && registCallback != NULL) || (mRegistingType == REGIST_PORT_TYPE_GET && gpcb != NULL)){
		log_info("use no block method");
		return E_TRANC_NONBLOCK;
	}

	/// wait stack response
	pthread_mutex_lock(&mutex_regist);	
	if(pthread_cond_timedwait(&goOnCond, &mutex_regist, &ts) == ETIMEDOUT){
		mRegistResult = E_TRANC_TIMEOUT;
	}
	pthread_mutex_unlock(&mutex_regist);

	canBeRemoved = mRegistResult==1 ? 0 : 1;
	return mRegistResult != 1 ? E_TRANC_TIMEOUT : mRegistedPort;
}
